//读取本文件参数代码示例: Vue.prototype.$my.xxx()、this.$my.xxx()
import Vue from 'vue'
export default {
    goto, //goto通用跳转
    ajax, //Api请求
    toast, //toast简化封装
    confirm, //confirm确认提示-框简化封装
    setCache, //设置缓存
    getCache, //获取缓存
    delCache, //删除缓存
	filterSame, //过滤重复数据
    join, //合并两个object数组
    getPush, //小程序订阅消息权限接口
    removeArray, //删除对象数组中某对象
    arr2var, //读取多层级数组变量
    fingerprintVerified, //纹验证
    UrlParse, //解析url参数
    trim, //移除字符串左右两端的指定字符
    ltrim, //移除字符串左边的指定字符
    rtrim, //移除字符串右边指定字符
    replaceSymbol //替换symbol字符中的特殊字符，以适应正则
};

/**
 * goto通用跳转
 * @param {string} url 跳转链接
 * @param {string} type 跳转类型（非必填，可选值：webview:打开http页面、switchTab:跳转到主菜单、reLaunch:关闭所有页面并打开、redirectTo:关闭当前页面并跳转、navigateTo:保留当前页面并跳转）
 * @param {string} checklogin 验证登录，如：checklogin、checkLogin、check_login
 * 使用例子：
 *			例1、goto('/pages/member/member'); //跳转至本地页面, 必须以/pages开头, 当存在于Config.js>main_urls设置时自动链接存在于main_urls数组中默认type=switchTab, 否则不存在main_urls时则默认type=redirectTo
 * 			例2、goto('/pages/ucenter/login', 'redirectTo'); //redirectTo方式打开页面（打开子窗口）
 * 			例3、goto('goods/detail/', 'webview'); //webview方式打开页面，当第一个url参数非http开头时自动加API前缀：project_url+'/goods/detail/'
 * 			例4、goto('https://www.baidu.com'); //webview打开, 当有http开头时，自动以webview打开页面，此时type参数无效
 * 		    例5、goto('XCX:小程序的APPID:/page/index/index') //跳转小程序
 * 			例6、goto('msg:模块升级，暂时维护中...'); //弹出toast提示（使用场景：后台链接设置时，临时要做屏蔽链接，只弹出提示）
 * 			例7、goto('back'); //返回上一页面（关闭当前子窗口）
 *			注：除url包含http 和 type=webview这两种情形，其它都会以应用内页面的方式跳转。url可以是含有/pages/前缀的完整地址，也可以不含/pages/前缀的短地址（注：如果有分包的话，那只有主包的页面可以用短地址，分包的必须用完整地址）
 */
function goto(url, type='', checklogin='') {
    //url为空时，直接return
	if(!url) {
	    console.log('url为空，goto跳转失败');
	    return;
    }
	//跳转小程序：XCX开头时说明是打开小程序（小程序链接示例 》 XCX:小程序的APPID:/page/index/index）
    if(url.substring(0,4)=='XCX:'){
        url = url.split(":");
        uni.navigateToMiniProgram({
            appId: typeof(url[1])!='undefined' ? url[1] : '',
            path: typeof(url[2])!='undefined' ? url[2] : 'pages/index/index',
            extraData: {//携带参数
                //'data1': 'test'
            },
            success(res) { }// 打开成功
        })
        return;
    }
	//呼出提示内容，不跳转
	if(url.indexOf('msg:') != -1){
		let text = url.split('msg:')[1];
		Vue.prototype.toast(text);
		return;
	}
	//返回上一页面
    if(url==='back') {
        uni.navigateBack();
        return;
    }
	//登录检查
	if(checklogin=='checklogin' || checklogin=='checkLogin' || checklogin=='check_login'){
		var member = Vue.prototype.getCache('member');
		//未登录时，直接跳转到登录页面
		if(!member || !member.token) {
			Vue.prototype.goto('/pages/ucenter/login');
			return;
		}
		//已登录，检查是否需要指纹验证（当有开启指纹时，每个APP生命周期只验证一次指纹）
		else {
			//指纹验证
			Vue.prototype.$my.fingerprintVerified();
		}
	}
	//url是http://或https://开头的，type强制指定为webview
	if(url.indexOf('http://')===0 || url.indexOf('https://')===0)
		type = 'webview';
	//type是webview而url又不是http开头的，自动构造完整url
	if(type=='webview' && url.indexOf('http')!==0){
		if(url.indexOf('/')===0){
			url = Vue.prototype.$config.project_url + url.substr(1);
		}else{
			url = Vue.prototype.$config.project_url + url;
		}
	}
	//webview打开
	if(type=='webview'){
		console.log('webview打开远程http链接:'+url);
		uni.navigateTo({
			url:'/pages/webview/webview?url=' + url
		})
		return;
	}
	//type为空，则判断当前url是否是主页，主页时type=switchTab, 否则type=redirectTo
    if(type=='' && Vue.prototype.$config.main_urls.indexOf(url)>-1)
        type='switchTab'
	//应用内页面跳转
	switch (type) {
		case 'switchTab':
			uni.switchTab({
				url
			});
			break;
		case 'reLaunch':
			uni.reLaunch({
				url:url,
				fail(){
					Vue.prototype.toast('reLaunch执行失败，可能是页面路径不存在：'+url);
				}
			});
			break;
		case 'redirectTo':
			uni.redirectTo({
				url:url,
				fail(){
					Vue.prototype.toast('redirectTo执行失败，可能是页面路径不存在：'+url);
				}
			});
			break;
		default:
			uni.navigateTo({
				url:url,
				fail(){
					Vue.prototype.toast('navigateTo执行失败，可能是页面路径不存在：'+url);
				}
			});
	}
}

/**
 * Api请求
 * @param {object} params...
 * 				   params.loading loading加载提示框（默认不显示）
 * 				   params.loadTitle loading提示文字信息
 * 				   params.fromPage 请求来自于某页面（目前仅在登录完成后返回某页面有体现）
 *  			   params.url Api请求地址
 * 				   params.method 请求数据类型，默认GET（GET，POST，PUT，DELETE，CONNECT，HEAD，OPTIONS，TRACE）
 * 				   params.data 请求的参数
 *  			   params.token 设置请求的 header
 * 注：ajax返回的是代理对象，需要then来接收返回值，有两个返回值，一般只接收第一个，第二个是请求失败的错误信息
 * 使用方法示例：
                this.ajax({
                    url:'xxx',
                    data:{aa:'xxx',bb:'xxx'}
                }).then(function(res){
                    console.log(res); //result就是返回的数组或对象
                    if(res.code===200) {
                        this.toast('操作成功');
                    } else {
                        this.toast(res.msg);
                    }
                });
 */
function ajax(params) {
	return new Promise( (resolve, reject) => {
		// 获取用户信息
		const member = Vue.prototype.getCache('member');
		if (params.loading)
        uni.showLoading({
            title: params.loadTitle ? params.loadTitle :'努力加载中...',
            // 是否显示透明蒙层，防止触摸穿透，默认: false
            mask: true,
        })

        //url非http开头时, 加MyUrl前缀
	    if(params.url.indexOf('http://')!==0 && params.url.indexOf('https://')!==0)
	        params.url = Vue.prototype.$config.apiRoot + params.url;

		console.log('ajax请求：' + params.url + (params.data?'?' + JSON.stringify(params.data):''));

		uni.request({
			url: params.url,
			data: params.data,
			method: params.method,
			header: {
				'uid': member?member.id:'',//自定义请求头信息
				'token': member?member.token:'',//自定义请求头信息
				'content-type': 'application/x-www-form-urlencoded', //注意：POST请求方式一定要加header头。不加 header头会默认为 OPTIONS
			},
			success: (res) => {
				res = res.data;
				if(res.code == 300){
					// api返回的错误信息
					console.log('API返回的错误信息：' + JSON.stringify(res.data));
					Vue.prototype.toast(res.msg);
					//返回结果
					resolve(res);
				}else{
				    //返回结果
					resolve(res);
				}
			},
			fail: (err) => {
				reject(err.data)
				let code = err.code;
				switch (code) {
					case 1000:
					// do something
					break;
					case 2000:
					// do something
					break;
				}
			},
			complete: () => {
				if (params.loading)
					uni.hideLoading();
			}
		});
	});
}

/**
 * toast简化封装
 * @param title 提示的文字
 * @param time 时长，毫秒，默认1500（即1.5秒）
 * @param mask 是否显示遮罩，为空时默认false
 * @param icon 图标，为空时默认值为none不用图标
 * 示例1、普通调用：this.toast('提示文字')、this.$my.toast('提示文字')、Vue.prototype.toast('提示文字')、Vue.prototype.$my.toast('提示文字')
 * 示例2、回调：this.toast('操作成功').then(function(){ self.toast('1.5秒后执行回调'); });
 */
function toast(title, time=1500, mask=false, icon='none') {
    return new Promise( (resolve, reject) => {
        //调用原生toast方法
        uni.showToast({
            title,
            time,
            mask,
            icon,
            success: () => {
                //延迟时间
                setTimeout(function() {
                    resolve(true);
                }, time)
            }
        });
	});
}
/**
 * confirm确认提示-框简化封装
 * 示例：
        this.confirm('确定要删除该地址吗？').then(function(res){
            if(res){
                //点击了确定
            }
            else {
                //点击了取消
            }
        });
 */
function confirm(params={}) {
	return new Promise( (resolve, reject) => {
		uni.showModal({
			title: params.title?params.title:'提示', //'提示',
			content: (typeof(params)=='string')?params:(params.content?params.content:''), //'确定要删除该地址吗？',
			confirmText: params.confirmText?params.confirmText:'确定', //'确定',
			cancelText: params.cancelText?params.cancelText:'取消', //'点错了',
			success: (e)=>{
				if(e.confirm) {
					resolve(true);
				} else {
					resolve(false);
				}
			}
		})
	})
}

/**
 * 设置storage缓存
 */
function setCache(key,val) {
	uni.setStorageSync(key,val);
}
/**
 * 获取storage缓存
 * @param key 变量名
 * @param defaultText 默认值
 * DEMO：
        //读取一个缓存
        this.getCache('member')
        //读取多层级变量
        this.getCache('member.id')
        //读取多层级变量
        this.getCache('member', '我是默认值')
 */
function getCache(key, defaultText='') {
    //存在字符.时
    if(key.indexOf('.')>=1) {
        //以.号分割
        let keys = key.split(".");
        //以keys[0]为变量名，读取storage缓存参数
        let result = uni.getStorageSync(keys[0]);
        //组合多级变量名
        keys = keys.slice(1);
        //无多级变量名时直接return result
        if(keys==='')
            return result;
        //将keys以.合并为字符串
        keys = keys.join('.');
        //通过arr2var读取多级变量
        result = Vue.prototype.arr2var(result, keys)
        if(!result)
            result = defaultText;
        return result;
    }
    //单一变量名时，直接取值并return
    else {
        let result = uni.getStorageSync(key);
        if(!result)
            result = defaultText;
        return result;
    }
}
/**
 * 删除storage缓存
 */
function delCache(key) {
	uni.removeStorageSync(key)
}

/**
 * 过滤重复数据，用于瀑布流分页加载，防止最近产生的新数据导致有重复数据
 * @param array res api获取到的最新分页数据
 * @param array mainList 总列表数据
 * @param array num 从总列表数据list中取最近N条数据(默认20)，用于跟api获取到的最新分页数据循环做对比去重
 * 注：
 */
function filterSame(res, mainList, num=20) {
    //从总列表数据list中取最近20条数据，然后跟当前api最新一页数据循环做对比去重
    let temp_list = mainList.slice(-num);
    //重新定义个变量，同时防止指针干扰
    let temp_res = JSON.parse(JSON.stringify(res));
    if(temp_list.length>0)
    temp_list.forEach(function(items){
        //循环api获取的新一页数据
        if(res.length>0)
        res.forEach(function(item){
            //console.log('items:',items.id,'item:',item.id);
            //发现相同的值时，移除相同的值
            if(items.id == item.id) {
                //删除相同的值
                temp_res = temp_res.filter((i) => {
                    return i.id != item.id;
                })
            }
        });
    });
    return temp_res;
}

/**
 * 合并两个object数组
 * 特别注意：必须保证obj1为数组，如果Obj1为{}这种非数组，就会出现这样的报错：Uncaught TypeError: obj1.concat is not a function
 */
function join(obj1,obj2) {
	//obj1：非object 或 为null时，初始化为数组
	if(typeof(obj1)!='object' || obj1==null)
		obj1 = [];
	//必须保证obj1为数组，object时得转为数组格式
	else if(typeof(obj1)=='object' && obj1)
		obj1 = [].concat(obj1);
	if(typeof(obj2)!='object' && typeof(obj2)=='undefined')
		obj2 = [];
	//console.log('obj1::::'+JSON.stringify(obj1));
	//console.log('obj2::::'+JSON.stringify(obj2));
	return obj1.concat(obj2);
}

/**
 * 小程序订阅消息权限接口（注意：只能通过点击事件调用，或者支付回调时触发弹窗)
 */
function getPush() {
	uni.requestSubscribeMessage({
		//模板ID
		tmplIds: ['D31vupIiaQRatmeHPjXjX_1_CYuj4_uG6H6Y0DqlIGU'],
		success (res) {
			console.log('授权成功'+res['D31vupIiaQRatmeHPjXjX_1_CYuj4_uG6H6Y0DqlIGU']);
		},
		fail:function(res){
			console.log(res);
		}
	});
}

/**
 * 删除对象数组中某对象（删除指定的值）
 * _arr 对象数组
 * _obj 删除的值
 */
function removeArray(_arr, _obj) {
	var length = _arr.length;
	for (var i = 0; i < length; i++) {
		if (JSON.stringify(_arr[i]) == JSON.stringify(_obj)) {
			_arr.splice(i, 1); //删除下标为i的元素
			return _arr;
		}
	}
}

/**
 * 读取多层级数组变量
 * 如：arr2var(result,'params.aaa.bbb')
 * 防止undefined报错
 */
function arr2var(arr,key,_default) {
	//默认值初始化
	if(typeof(_default)=='undefined')
		_default = '';
	//arr不是数组时，arr原路返回
	if(typeof(arr)!='object')
		return _default;
	//key为空或为undefined时
	if(key=='' || typeof(key)=='undefined')
		return _default;
	//result
	var result = arr;
	//循环中使用的临时key名称
	var name = '';
	//将key以.分割成数组
	var keys = key.split(".");
	for(var kkk in keys){
		name = keys[kkk];
		//不存在值时，直接返回
		if(typeof(result[name])=='undefined')
			return _default;
		//继续循环
		else
			result = result[name];
	}
	return result;
}

/**
 * 指纹验证
 * 如验证失败/点了取消则返回上一页面
 */
function fingerprintVerified() {
	//获取是否开启指纹验证
	var Fingerprint =  Vue.prototype.getCache("Fingerprint");
	if(Fingerprint){
		// #ifdef APP-PLUS || MP-WEIXIN
		//获取本机支持认证方式
		uni.checkIsSupportSoterAuthentication({
			success(res) {
				// 如果当前设备支持生物识别方式，且支持指纹识别方式 ，且是新的session
				if(res.supportMode && res.supportMode.includes('fingerPrint')){
					//获取缓存的sessionID
					var oldSessionId = Vue.prototype.getCache("SessionId");
					Vue.prototype.ajax({ url: 'member/getSessionId' }).then(function(msg){
						var newSessionId = msg.data;
						//如果新获取的session和缓存的session不一致
						if(newSessionId != oldSessionId){
							//保存下最新的session
							Vue.prototype.setCache("SessionId",newSessionId);

							/**
							 * uni.checkIsSoterEnrolledInDevice : 获取设备内是否录入指纹信息
							 *  checkAuthMode: 'fingerPrint', // 检验指纹信息
							 * */
							uni.checkIsSoterEnrolledInDevice({
								checkAuthMode: 'fingerPrint', // 检验指纹信息
								success(res) {
									console.log(res.isEnrolled)
									if(res.isEnrolled == true){
										/**
										 * 开始 SOTER 生物认证
										 * 执行成功，进行后续操作
										 * */
										uni.startSoterAuthentication({
											requestAuthModes: ['fingerPrint'],
											/*
												挑战因子。挑战因子为调用者为此次生物鉴权准备的
												用于签名的字符串关键识别信息，将作为 resultJSON 的一部分，
												供调用者识别本次请求。
												例如：如果场景为请求用户对某订单进行授权确认，
												则可以将订单号填入此参数。
											*/
											challenge: '123456',
											authContent: '请用指纹解锁',
											success(res) {
												//操作成功
											},
											fail(err) {
												console.log(err,'出错了~');
												//取消指纹验证的话
												if(err.errCode==90008){
													Vue.prototype.setCache("SessionId",'');
													uni.navigateBack({delta:1});
												}
											},
										})
									}else{
										//此设备未录入指纹，请到设置中开启
										Vue.prototype.setCache("Fingerprint",false);
									}
								},
								fail(err) {
									//此设备未录入指纹，请到设置中开启
									Vue.prototype.setCache("Fingerprint",false);
								}
							})
						}
					});
				}
				else{
					//此设备不支持指纹识别功能
					Vue.prototype.setCache("Fingerprint",false);
				}
			},
			fail(err) {
				//此设备不支持指纹识别功能
				 Vue.prototype.setCache("Fingerprint",false);
			}
		})
		// #endif
	}
}

/**
 * 解析url参数
 * @param {String}  url 解析传递过来的url参数为obj对象
 * ?id=111&name=567  => {id:111,name:567}
 */
function UrlParse(url) {
	const obj = {}
	const scene = decodeURIComponent(url)
	const reg = /[^?&]+=[^?&%]+/g;
	const arr = scene.match(reg);
	arr.forEach((item) => {
		const key = item.split('=')[0];
		const val = item.split('=')[1];
		obj[key] = val;
	})
	return obj;
}

/**
 * 过滤字符串两边字符
 * 示例1：alert(rtrim('1111.1000','0'));
 * 示例2：alert(trim('、测试、','、'));
 * 示例3：alert(rtrim("'测试'","'"));
 * 示例4：alert(trim('1111.1000',''));
 */
/**
 * 移除字符串左右两端的指定字符
 * @param string str 要过滤的目标字符串
 * @param string symbol 要过滤掉的字符（非必填：不传值时为过滤英文空格）
 */
function trim(str, symbol) {
	symbol = Vue.prototype.$my.replaceSymbol(symbol);
	return str.replace(new RegExp('^'+symbol+'+|'+symbol+'+$', 'g'), "");
}
/**
 * 移除字符串左边的指定字符
 * @param string str 要过滤的目标字符串
 * @param string symbol 要过滤掉的字符（非必填：不传值时为过滤英文空格）
 */
function ltrim(str, symbol) {
	symbol = Vue.prototype.$my.replaceSymbol(symbol);
	return str.replace(new RegExp('^'+symbol+'+', 'g'),"");
}
/**
 * 移除字符串右边指定字符
 * @param string str 要过滤的目标字符串
 * @param string symbol 要过滤掉的字符（非必填：不传值时为过滤英文空格）
 */
function rtrim(str, symbol) {
	symbol = Vue.prototype.$my.replaceSymbol(symbol);
	return str.replace(new RegExp(''+symbol+'+$', 'g'),"");
}
/**
 * 替换symbol字符中的特殊字符，以适应正则
 * 本函数将字符串中含有 . \\ + * ? [ ^ ] ( $ ) 等字符的前面加入反斜线 "\" 符号
 */
function replaceSymbol(symbol) {
	//未传值时，给个默认值为英文空格（去除字符两端的空格）
	if(typeof(symbol)=='undefined' || symbol=='')
		return ' ';
	//替换symbol字符中的特殊字符，以适应正则
	else {
		symbol = symbol.toString()
		return symbol.replace(/([\.\\\+\*\?\[\^\]\(\$\)])/g,"\\$1");
	}
}